/*
 * FixedSizeBlockSequentialFile.h
 *
 *  Created on: Nov 26, 2012
 *      Author: m
 */

#ifndef FIXEDSIZEBLOCKSEQUENTIALFILE_H_
#define FIXEDSIZEBLOCKSEQUENTIALFILE_H_

#include "physical_layer_commons.h"
#include "FixedSizeBlockFile.h"

namespace physical
{

/**
 * Archivo secuencial de Bloques de tamaño fijo
 *
 * Recibe como parámetro el tamaño de bloque
 */
template < size_t T >
class FixedSizeBlockSequentialFile
{
public:

    /**
     * Constructor por defecto
     *
     * Crea un FixedSizeBlockSequentialFile
     *  sin asociarle ningún archvo
     */
    FixedSizeBlockSequentialFile() :
        m_file( T ),
        nextRecord(0)
    {
    }

    /**
     * Constructor por valor
     *
     * Crea un FixedSizeBlockSequentialFile
     *  y le asocia un archvo, abierto en
     *  el modo indicado. Si no se indica
     *  ningún modo se abre en el modo
     *  por defecto ( in | out | app )
     *
     * @param filename Nombre del archivo a asociar
     * @param mode Modo de apertura. Valor por
     *              defecto: ( in | out | app )
     */
    FixedSizeBlockSequentialFile( const char *filename,
            openmode mode = s_defaultOpenmode ) :
        m_file( T, filename, mode ),
        nextRecord(0)
    {
    }

    /**
     * Destructor
     */
    virtual ~FixedSizeBlockSequentialFile()
    {
        this->close();
    }

    /**
     * Devuelve el próximo bloque
     *
     * @param block Bloque donde se guarda el
     *               siguiente registro
     */
    void get( byte* block )
    {
        m_file.readBlock( nextRecord, block );
        nextRecord++;
    }

    /**
     * Inserta un registro al final del archivo
     *
     * @param block Bloque a guardar al final
     *               del archivo
     * @return Posición en la que se guardó el elemento.
     *          La posición del primer elemento es 0
     */
    size_t put( const byte* block )
    {
        size_t nextPosition = m_file.getBlocksCount();

        m_file.writeBlock( nextPosition , block );

        return nextPosition;
    }

    /**
     * Verifica si existe otro registro para leer
     *
     * @return true si existen registros para leer,
     *          false en caso contrario
     */
    bool hasNext()
    {
        return nextRecord < m_file.getBlocksCount();
    }

    /**
     * Asocia un archivo al blockFile
     *
     * @param filename Nombre del archivo
     * @param mode Modo de apertura. Valor por defecto: ( in | out | app )
     */
    void open( const char* filename, openmode mode = s_defaultOpenmode )
    {
        nextRecord = 0;
        m_file.open( filename, mode );
    }

    /**
     * Desasocia un archivo del blockFile
     */
    void close()
    {
        m_file.close();
    }

protected:
    static const openmode s_defaultOpenmode =
            std::ios_base::in | std::ios_base::out | std::ios_base::app;

    FixedSizeBlockFile m_file;
    blockNumber nextRecord;
};

} /* namespace physical */
#endif /* FIXEDSIZEBLOCKSEQUENTIALFILE_H_ */
